home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-10-04 | 40.8 KB | 1,229 lines |
- ;;; -*- Mode:Lisp; Package:Weyli; Base:10; Lowercase:T; Syntax:Common-Lisp -*-
-
- ;; $Id: bigfloat.lisp,v 2.13 1991/10/04 22:42:51 rz Exp $
-
- ;; Arbitrary Precision Real Arithmetic System
- ;; by Tateaki Sasaki
- ;; The UNIVERSITY OF UTAH, MARCH 1979
-
- ;; For design philosophy and characteristics of this system, see T. Sasaki,
- ;; ``An Arbitrary Precision Real Arithmetic Package In Reduce,''
- ;; Proceedings of Eurosam '79, Marseille (FRANCE), June 1979.
-
- ;; For Implementation notes and using this system, see T. Sasaki,
- ;; ``Manual For Arbitrary Precision Real Arithmetic System in Reduce,'
- ;; Operating Report of Utah Symbolic Computation Group
-
- ;; In order to speed up this system, you have only to rewrite four
- ;; routines (DECPREC!, INCPREC!, PRECI!, AND ROUND!LAST)
- ;; machine-dependently.
-
- ;; This function constructs an internal representation of a number
- ;; 'n' composed of the mantissa MT and the exponent EP with the base
- ;; 10. The magnitude of the number thus constructed is hence
- ;; MT*10^EP.
-
- ;; **** CAUTION! MT and EP are integers. So, EP denotes the order of
- ;; the last figure in 'N', WHERE order(N)=K if 10**K <=
- ;; ABS(N) < 10**(K+1), with the exception order(0)=0.
- ;;
-
- ;; The number 'n' is said to be of precision 'k' if its mantissa is a
- ;; k-figure number. MT and EP are any integers (positive or
- ;; negative). So, you can handle any big or small numbers. in this
- ;; sense, 'BF' denotes a big-floating-point number. Hereafter, an
- ;; internal representation of a number constructed by MAKE-BIGFLOAT is
- ;; referred to as a big-float representation.
-
- (in-package "WEYLI")
-
- (defmethod print-object ((d real-numbers) stream)
- #+Genera
- (format stream "~'bR~(~D)" (fp-precision d))
- #-Genera
- (format stream "R(~D)" (fp-precision d)))
-
-
- (defsubst make-bigfloat (domain mantissa exponent)
- (make-instance 'bigfloat :domain domain
- :mantissa mantissa :exponent exponent))
-
- ;; This function returns t if x is a big-float representation, else it
- ;; returns NIL.
- (defun bigfloatp (x)
- (eql (class-name (class-of x)) 'bigfloat))
-
- (defmethod number? ((element bigfloat))
- t)
-
- ;; This function counts the precision of a bigfloat 'n'.
- ;;
- ;; FIXTHIS: The 1+ below is total kludge. This whole package needs
- ;; to be rewritten sometime soon.
- (defun preci! (nmbr)
- (let* ((mt (1+ (abs (bigfloat-mantissa nmbr))))
- (len (integer-length mt)))
- (if (< len 10)
- (lisp:ceiling (lisp:log mt 10))
- (lisp:ceiling (lisp:+ (lisp:/ (lisp:+ len -10) #.(lisp:log 10 2))
- (lisp:log (lisp:ash mt (lisp:- 10 len)) 10))))))
-
- ;; This function counts the order of a bigfloat 'n'.
- ;; **** ORDER(N)=K IF 10**K <= ABS(N) < 10**(K+1)
- ;; **** WHEN N IS NOT 0, AND ORDER(0)=0.
- (defun order! (nmbr)
- (if (lisp:zerop (bigfloat-mantissa nmbr)) 0
- (lisp:+ (preci! nmbr) (bigfloat-exponent nmbr) -1)))
-
- (defun convert-number->characters (number)
- (if (lisp:zerop number) (list #\0)
- (let ((chars ()))
- (loop with n = number
- and digit
- while (not (lisp:zerop n))
- do (multiple-value-setq (n digit) (lisp:truncate n 10))
- (push (digit-char digit) chars))
- chars)))
-
- (defmethod print-object ((number bigfloat) stream)
- (setq number (round!mt number (lisp:- (fp-precision (domain-of number)) 2)))
- (with-slots (mantissa exponent) number
- (let ((u (convert-number->characters (abs mantissa)))
- k)
- (flet ((bfprin1 (u)
- (when (lisp:minusp mantissa)
- (push #\- u))
- ;; Suppress trailing zeroes
- (loop for v on (reverse u)
- while (and (char= (first v) #\0)
- (if (rest v) (char/= (second v) #\.)
- t))
- finally (setq u (nreverse v)))
- ;; Now print the number
- (loop for char in u
- do (write-char char stream))))
- (or (rest u) (push #\0 (rest u)))
- (push #\. (rest u))
- (bfprin1 u)
- (princ "B" stream)
- (setq u (convert-number->characters (abs (setq k (order! number)))))
- (setq u (cons (if (lisp:< k 0) #\- #\+)
- u))
- (loop for char in u
- do (write-char char stream))
- number))))
-
-
- ;;; Routines For Converting A Big-Float Number
-
- ;; This function converts a number N to an equivalent number the
- ;; precision of which is decreased by K.
- (defun decprec! (number k)
- (with-slots (exponent mantissa) number
- (make-bigfloat *domain*
- (lisp:truncate mantissa (lisp:expt 10 k))
- (lisp:+ exponent k))))
-
- ;; This function converts a number N to an equivalent
- ;; number the precision of which is increased by K.
- (defun incprec! (number k)
- (with-slots (exponent mantissa) number
- (make-bigfloat *domain*
- (lisp:* mantissa (lisp:expt 10 k))
- (lisp:- exponent k))))
-
- ;; This function converts a number to an equivalent number of precision
- ;; k by rounding or adding '0's.
- (defun conv!mt (number k)
- (unless (bigfloatp number)
- (error "Expected ~S to be a bigfloat" number))
- (unless (and (integerp k) (lisp:> k 0))
- (error "Expected ~S to be a positive integer" k))
- (cond ((lisp:zerop (setq k (lisp:- (preci! number) k)))
- number)
- ((lisp:< k 0) (incprec! number (lisp:- k)))
- (t (round!last (decprec! number (1- k))))))
-
- ;; This function converts a number 'n' to an equivalent number having
- ;; the exponent k by rounding 'n' or adding '0's to 'n'.
- (defun conv!ep (nmbr k)
- (unless (bigfloatp nmbr)
- (error "Invalid argument to conv!ep: ~S" nmbr))
- (unless (integerp k)
- (error "Invalid second argument to conv!ep: ~S" k))
- (cond ((lisp:zerop (setq k (lisp:- k (bigfloat-exponent nmbr))))
- nmbr)
- ((lisp:< k 0) (incprec! nmbr (lisp:- k)))
- (t (round!last (decprec! nmbr (lisp:- k 1))))))
-
- ;; This function returns a given number N unchanged if its precision
- ;; is not greater than K, else it cuts off its mantissa at the (K+1)th
- ;; place and returns an equivalent number of precision K.
- ;; **** CAUTION! NO ROUNDING IS MADE.
- (defun cut!mt (nmbr k)
- (declare (fixnum k))
- (unless (bigfloatp nmbr)
- (error "Invalid argument to cut!mt: ~S" nmbr))
- (unless (and (integerp k) (lisp:> k 0))
- (error "Invalid precision to cut!mt: ~D" k))
- (if (lisp:plusp (setq k (lisp:- (preci! nmbr) k)))
- (decprec! nmbr k)
- nmbr))
-
- ;; This function returns a given number N unchanged if its exponent is
- ;; not less than K, else it cuts off its mantissa and returns an
- ;; equivalent number of exponent K.
- ;; **** CAUTION! NO ROUNDING IS MADE.
- (defun cut!ep (nmbr k)
- (unless (bigfloatp nmbr)
- (error "Invalid argument to cut!ep: ~S" nmbr))
- (unless (integerp k)
- (error "Invalid precision to cut!ep: ~D" k))
- (if (not (lisp:> (setq k (lisp:- k (bigfloat-exponent nmbr))) 0))
- nmbr
- (decprec! nmbr k)))
-
- ;; This function rounds a number N at the (K+1)th place and returns an
- ;; equivalent number of precision K if the precision of N is greater
- ;; than K, else it returns the given number unchanged.
- (defun round!mt (nmbr k)
- (unless (bigfloatp nmbr)
- (error "Invalid argument to round!mt: ~S" nmbr))
- (unless (and (integerp k) (not (lisp:minusp k)))
- (error "Invalid precision to round!mt: ~D" k))
- (cond ((lisp:minusp (setq k (lisp:- (preci! nmbr) k 1)))
- nmbr)
- ((equal k 0) (round!last nmbr))
- (t (round!last (decprec! nmbr k)))))
-
- ;; This function rounds a number N and returns an equivalent number
- ;; having the exponent K if the exponent of N is less than K, else it
- ;; returns the given number unchanged.
- (defun round!ep (nmbr k)
- (unless (bigfloatp nmbr)
- (error "Invalid argument to cut!ep: ~S" nmbr))
- (unless (integerp k)
- (error "Invalid precision to cut!ep: ~D" k))
- (cond ((lisp:< (setq k (lisp:- (lisp:1- k) (bigfloat-exponent nmbr))) 0)
- nmbr)
- ((equal k 0) (round!last nmbr))
- (t (round!last (decprec! nmbr k)))))
-
- ;; This function rounds a number N at its last place.
- (defun round!last (nmbr)
- (let ((abs-nmbr (abs (bigfloat-mantissa nmbr)))
- n)
- (setq n (if (lisp:< (rem abs-nmbr 10) 5)
- (lisp:truncate abs-nmbr 10)
- (1+ (lisp:truncate abs-nmbr 10))))
- (if (lisp:minusp (bigfloat-mantissa nmbr)) (setq n (lisp:- n)))
- (make-bigfloat *domain* n (lisp:1+ (bigfloat-exponent nmbr)))))
-
- ;;; Routines for reading/printing numbers
-
- ;; This function reads a long number N represented by a list in a way
- ;; described below, and constructs a big-float representation of N.
- ;; Using this function, you can input any long floating-point numbers
- ;; without difficulty. L is a list of integers, the first element of
- ;; which gives the order of N and all the next elements when
- ;; concatenated give the mantissa of N.
- ;; **** ORDER(N)=K IF 10**K <= ABS(N) < 10**(K+1).
-
- (defun read!lnum (l)
- (loop for q in l
- unless (integerp q)
- do (error "Invalid argument to read!lnum: ~S" q))
- (loop for term in (rest l)
- for k = (lisp:ceiling (integer-length term) #.(lisp:log 10 2))
- with mt = 0
- and ep = (1+ (first l))
- do (setq mt (lisp:+ (lisp:* mt (lisp:expt 10 k)) (abs term)))
- (setq ep (lisp:- ep k))
- finally (return
- (make-bigfloat *domain*
- (if (lisp:plusp (second l)) mt (lisp:- mt))
- ep))))
-
- ;; This function reads a long number N represented by a list in a way
- ;; described below, and constructs a big-float representation of N.
- ;; Using this function, you can input any long floating-point numbers
- ;; without difficulty. L is a list of integers, the first element of
- ;; which gives the order of N and all the next elements when
- ;; concatenated give the mantissa of N.
- ;; **** ORDER(N)=K IF 10**K <= ABS(N) < 10**(K+1).
-
- (defun read!num (n)
- (let ((exponent 0))
- (multiple-value-bind (integer j)
- (parse-integer n :junk-allowed t)
- (unless integer
- (setq integer 0))
- (cond ((char= (aref n j) #\.)
- (multiple-value-bind (fraction i)
- (parse-integer n :start (1+ j) :junk-allowed t)
- (setq integer (lisp:+ (lisp:* integer
- (lisp:expt 10 (lisp:- i j 1)))
- fraction))
- (decf exponent (lisp:- i j 1)))))
- (make-bigfloat *domain* integer exponent))))
-
- ;;; Arithmetic manipulation routines
-
- (defun bf-abs (nmbr)
- (if (lisp:> (bigfloat-mantissa nmbr) 0) nmbr
- (make-bigfloat *domain*
- (lisp:- (bigfloat-mantissa nmbr))
- (bigfloat-exponent nmbr))))
-
- (defun bf-minus (nmbr)
- (make-bigfloat *domain*
- (lisp:- (bigfloat-mantissa nmbr))
- (bigfloat-exponent nmbr)))
-
- (defun bf-plus (n1 n2)
- (let ((e1 (bigfloat-exponent n1)) (e2 (bigfloat-exponent n2)))
- (cond ((lisp:= e1 e2)
- (make-bigfloat *domain*
- (lisp:+ (bigfloat-mantissa n1) (bigfloat-mantissa n2))
- e1))
- ((lisp:> e1 e2)
- (make-bigfloat *domain*
- (lisp:+ (bigfloat-mantissa (incprec! n1 (lisp:- e1 e2)))
- (bigfloat-mantissa n2))
- e2))
- (t (make-bigfloat *domain*
- (lisp:+ (bigfloat-mantissa n1)
- (bigfloat-mantissa (incprec! n2 (lisp:- e2 e1))))
- e1)))))
-
- (defun bf-difference (n1 n2)
- (let ((e1 (bigfloat-exponent n1)) (e2 (bigfloat-exponent n2)))
- (cond ((lisp:= e1 e2)
- (make-bigfloat *domain*
- (lisp:- (bigfloat-mantissa n1) (bigfloat-mantissa n2))
- e1))
- ((lisp:> e1 e2)
- (make-bigfloat *domain*
- (lisp:- (bigfloat-mantissa (incprec! n1 (lisp:- e1 e2)))
- (bigfloat-mantissa n2))
- e2))
- (t
- (make-bigfloat *domain*
- (lisp:- (bigfloat-mantissa n1)
- (bigfloat-mantissa (incprec! n2 (lisp:- e2 e1))))
- e1)))))
-
- (defun bf-times (n1 n2)
- (make-bigfloat *domain*
- (lisp:* (bigfloat-mantissa n1) (bigfloat-mantissa n2))
- (lisp:+ (bigfloat-exponent n1) (bigfloat-exponent n2))))
-
- (defun bf-quotient (n1 n2 k)
- (round!mt
- (with-slots (mantissa exponent) (conv!mt n1 (lisp:+ k (preci! n2) 1))
- (make-bigfloat *domain*
- (lisp:truncate mantissa (bigfloat-mantissa n2))
- (lisp:- exponent (bigfloat-exponent n2))))
- k))
-
- ;; This function calculates the kth power of 'n'. The result will
- ;; become a long number if abs(k) >> 1.
- (defun bf-expt (number k precision)
- (if (lisp:< k 0)
- (/ (make-bigfloat *domain* 1 0)
- (bf-expt number (lisp:- k) precision))
- (%funcall (repeated-squaring
- (lambda (a b) (round!mt (bf-times a b) precision))
- (make-bigfloat *domain* 1 0))
- number k)))
-
- ;; This function calculates the integer quotient of 'n1' and 'n2',
- ;; just as the quotient" for integers does.
- (defun bf-floor (n1 n2)
- (let ((e1 (bigfloat-exponent n1))
- (e2 (bigfloat-exponent n2)))
- (cond ((lisp:= e1 e2)
- (make-bigfloat *domain*
- (lisp:truncate (bigfloat-mantissa n1) (bigfloat-mantissa n2))
- 0))
- ((lisp:> e1 e2)
- (bf-floor (incprec! n1 (lisp:- e1 e2)) n2))
- (t (bf-floor n1 (incprec! n2 (lisp:- e2 e1)))))))
-
- (defun bf-integer-part (num)
- (with-slots (exponent mantissa) num
- (if (lisp:zerop exponent) mantissa
- (lisp:* mantissa (lisp:expt 10 exponent)))))
-
- ;; This returns a lisp integer as its first return value (perhaps
- ;; this should be a floating point integer)?
-
- (defmethod floor ((number bigfloat) &optional modulus)
- (let ((domain (domain-of number))
- quo)
- (bind-domain-context domain
- (cond ((null modulus)
- (setq quo (cut!ep number 0))
- (values (bf-integer-part quo)
- (bf-difference number quo)))
- (t (setq modulus (coerce modulus (domain-of number)))
- (setq quo (bf-floor number modulus))
- (values (bf-integer-part quo)
- (bf-difference number (bf-times quo modulus))))))))
-
- (defmethod ceiling ((number bigfloat) &optional modulus)
- (let ((domain (domain-of number))
- quo)
- (bind-domain-context domain
- (cond ((null modulus)
- (setq quo (cut!ep number 0))
- (unless (eql quo number)
- (setq quo (+ 1 quo)))
- (values (bf-integer-part quo)
- (bf-difference number quo)))
- (t (setq modulus (coerce modulus (domain-of number)))
- (setq quo (bf-floor number modulus))
- (unless (eql quo (cut!ep quo 0))
- (setq quo (+ 1 quo)))
- (values (bf-integer-part quo)
- (bf-difference number (bf-times quo modulus))))))))
-
- (defmethod round ((number bigfloat) &optional modulus)
- (let ((domain (domain-of number))
- quo)
- (bind-domain-context domain
- (cond ((null modulus)
- (setq quo (floor (+ (coerce 0.5 domain) number)))
- (values quo
- (bf-difference number (coerce quo domain))))
- (t (setq modulus (coerce modulus domain))
- (setq quo (bf-floor (+ number (* (coerce 0.5 domain) modulus))
- modulus))
- (values quo
- (bf-difference
- number
- (bf-times (coerce quo domain) modulus))))))))
-
- (defmethod truncate ((number bigfloat) &optional modulus)
- (if (plus? number)
- (floor number modulus)
- (ceiling number modulus)))
-
-
- ;;; Arithmetic predicates
-
- ;; This function returns t if 'n1' > 'n2' else returns nil.
- (defmethod-binary > bigfloat (n1 n2)
- (with-slots ((e1 exponent)) n1
- (with-slots ((e2 exponent)) n2
- (cond ((lisp:= e1 e2)
- (lisp:> (bigfloat-mantissa n1) (bigfloat-mantissa n2)))
- ((lisp:> e1 e2)
- (lisp:> (bigfloat-mantissa (incprec! n1 (lisp:- e1 e2)))
- (bigfloat-mantissa n2)))
- ((lisp:> (bigfloat-mantissa n1)
- (bigfloat-mantissa (incprec! n2 (lisp:- e2 e1))))
- t)
- (t nil)))))
-
- (defmethod-binary < bigfloat (n1 n2)
- (with-slots ((e1 exponent)) n1
- (with-slots ((e2 exponent)) n2
- (cond ((lisp:= e1 e2)
- (lisp:< (bigfloat-mantissa n1) (bigfloat-mantissa n2)))
- ((lisp:< e1 e2)
- (lisp:< (bigfloat-mantissa (incprec! n1 (lisp:- e1 e2)))
- (bigfloat-mantissa n2)))
- ((lisp:< (bigfloat-mantissa n1)
- (bigfloat-mantissa (incprec! n2 (lisp:- e2 e1))))
- t)
- (t nil)))))
-
- (defmethod-binary = bigfloat (n1 n2)
- (with-slots ((e1 exponent)) n1
- (with-slots ((e2 exponent)) n2
- (and (lisp:= e1 e2)
- (lisp:= (bigfloat-mantissa n1) (bigfloat-mantissa n2))))))
-
- (defmethod-binary >= bigfloat (n1 n2)
- (with-slots ((e1 exponent)) n1
- (with-slots ((e2 exponent)) n2
- (cond ((lisp:= e1 e2)
- (lisp:>= (bigfloat-mantissa n1) (bigfloat-mantissa n2)))
- ((lisp:> e1 e2)
- (lisp:> (bigfloat-mantissa (incprec! n1 (lisp:- e1 e2)))
- (bigfloat-mantissa n2)))
- ((lisp:>= (bigfloat-mantissa n1)
- (bigfloat-mantissa (incprec! n2 (lisp:- e2 e1))))
- t)
- (t nil)))))
-
- (defmethod-binary <= bigfloat (n1 n2)
- (with-slots ((e1 exponent)) n1
- (with-slots ((e2 exponent)) n2
- (cond ((lisp:= e1 e2)
- (lisp:<= (bigfloat-mantissa n1) (bigfloat-mantissa n2)))
- ((lisp:< e1 e2)
- (lisp:< (bigfloat-mantissa (incprec! n1 (lisp:- e1 e2)))
- (bigfloat-mantissa n2)))
- ((lisp:<= (bigfloat-mantissa n1)
- (bigfloat-mantissa (incprec! n2 (lisp:- e2 e1))))
- t)
- (t nil)))))
-
- (defun bf-integerp (x)
- (and (bigfloatp x)
- (not (lisp:minusp (bigfloat-exponent x)))))
-
- (defmethod minus? ((x bigfloat))
- (lisp:minusp (bigfloat-mantissa x)))
-
- (defmethod plus? ((x bigfloat))
- (lisp:plusp (bigfloat-mantissa x)))
-
- (defmethod 0? ((number bigfloat))
- (equal (bigfloat-mantissa number) 0))
-
- (defmethod 1? ((number bigfloat))
- (and (equal (bigfloat-mantissa number) 1)
- (eql (bigfloat-exponent number) 0)))
-
- (defmethod abs ((number bigfloat))
- (bind-domain-context (domain-of number)
- (bf-abs number)))
-
- (defmethod minus ((number bigfloat))
- (bind-domain-context (domain-of number)
- (bf-minus number)))
-
- (defmethod-binary plus bigfloat (x y)
- (bind-domain-context domain
- (round!mt (bf-plus x y) (fp-precision domain))))
-
- (defmethod plus ((x bigfloat) (y float))
- (plus x (coerce y (domain-of x))))
-
- (defmethod plus ((x float) (y bigfloat))
- (plus (coerce x (domain-of y)) y))
-
- (defmethod-binary difference bigfloat (x y)
- (bind-domain-context domain
- (round!mt (bf-difference x y) (fp-precision domain))))
-
- (defmethod difference ((x bigfloat) (y float))
- (difference x (coerce y (domain-of x))))
-
- (defmethod difference ((x float) (y bigfloat))
- (difference (coerce x (domain-of y)) y))
-
- (defmethod-binary times bigfloat (x y)
- (bind-domain-context domain
- (round!mt (bf-times x y) (fp-precision domain))))
-
- (defmethod times ((x bigfloat) (y float))
- (times x (coerce y (domain-of x))))
-
- (defmethod times ((x float) (y bigfloat))
- (times (coerce x (domain-of y)) y))
-
- (defmethod-binary quotient bigfloat (x y)
- (bind-domain-context domain
- (round!mt (bf-quotient x y (fp-precision domain))
- (fp-precision domain))))
-
- (defmethod quotient ((x bigfloat) (y float))
- (quotient x (coerce y (domain-of x))))
-
- (defmethod quotient ((x float) (y bigfloat))
- (quotient (coerce x (domain-of y)) y))
-
- (defmethod expt ((number bigfloat) (k integer))
- (cond ((eql k 0) (make-bigfloat (domain-of number) 1 0))
- ((eql k 1) number)
- (t (let ((domain (domain-of number)))
- (bind-domain-context domain
- (bf-expt number k (fp-precision domain)))))))
-
-
- ;; Elementary Constants
-
- ;; This function returns the value of constant CNST of the precision
- ;; K, if it was calculated previously with, at least, the precision K,
- ;; else it returns :NOT-FOUND.
- (defun get!const (cnst k)
- (unless (atom cnst)
- (error "Invalid argument to get!const: ~S" cnst))
- (unless (and (integerp k) (> k 0))
- (error "Invalid precision to get!const: ~D" k))
- (let ((u (get cnst 'save!c)))
- (cond ((or (null u) (< (car u) k)) nil)
- ((equal (car u) k) (cdr u))
- (t (round!mt (cdr u) k)))))
-
- ;; This function saves the value of constant CNST for the later use.
- (defun save!const (cnst nmbr)
- (unless (atom cnst)
- (error "Invalid constant for save!const: ~S" cnst))
- (unless (bigfloatp nmbr)
- (error "Invalid argument to save!const: ~S" nmbr))
- (setf (get cnst 'save!c) (cons (preci! nmbr) nmbr)))
-
- ;; This function sets the value of constant CNST. CNST is the name of
- ;; the constant. L is a list of integers, which represents the value
- ;; of the constant in the way described in the function READ!LNUM.
- (defmacro set!const (constant digits)
- `(progn (save!const ',constant (read!lnum ',digits))
- ',constant))
-
- (set!const !pi
- (0 31415926535897932384626433832795028841971693993751058209749))
-
- (set!const !e
- (0 27182818284590452353602874713526624977572470936999595749669))
-
- (defmacro define-bfloat-constant (name &body form)
- `(defun ,name (prec)
- (let ((u (get!const ',name prec)))
- (when (eq u :not-found)
- (setq u ,@form)
- (save!const ',name u))
- u)))
-
- (defmethod pi-value ((domain real-numbers))
- (bind-domain-context domain
- (bf-pi (fp-precision domain))))
-
- (defun bf-pi (precision)
- (cond ((< precision 20)
- (round!mt (make-bigfloat *domain* 314159265358979323846 -20)
- precision))
- ((get!const '!pi precision))
- ((< precision 1000) (bf-pi-machin precision))
- (t (bf-pi-agm precision))))
-
- ;; This function calculates the value of `pi' with the precision K by
- ;; using Machin's identity:
- ;; PI = 16*ATAN(1/5) - 4*ATAN(1/239).
- ;; The calculation is performed mainly on integers.
- (defun bf-pi-machin (k)
- (let* ((k+3 (+ k 3))
- s
- (ss (lisp:truncate (expt 10 k+3) 5))
- (n ss)
- (m 1)
- (x -25)
- u)
- (loop while (not (lisp:zerop n)) do
- (setq n (lisp:truncate n x))
- (setq ss (+ ss (lisp:truncate n (setq m (+ m 2))))))
- (setq s (setq n (lisp:truncate (expt 10 k+3) 239)))
- (setq x (- (expt 239 2)))
- (setq m 1)
- (loop while (not (lisp:zerop n)) do
- (setq n (lisp:truncate n x))
- (setq s (+ s (lisp:truncate n (setq m (+ m 2))))))
- (setq u (round!mt (make-bigfloat *domain* (- (* 16 ss) (* 4 s)) (- k+3))
- k))
- (save!const '!pi u)
- u))
-
- ;; This function calculates the value of 'PI', with the precision K, by
- ;; the arithmetic-geometric mean method. (R. Brent, JACM vol.23, #2,
- ;; pp.242-251(1976).)
- (defun bf-pi-agm (k)
- (let* ((n 1)
- (k2 (+ k 2))
- (u (coerce 0.25 *domain*))
- (half (coerce 0.5 *domain*))
- (dcut (make-bigfloat *domain* 10 (- k2)))
- (x (coerce 1 *domain*))
- (y (bf-quotient x (bf-sqrt (coerce 2 *domain*) k2) k2))
- v)
- (loop while (> (bf-abs (bf-difference x y)) dcut) do
- (setq v x)
- (setq x (bf-times (bf-plus x y) half))
- (setq y (bf-sqrt (cut!ep (bf-times y v) (- k2)) k2))
- (setq v (bf-difference x v))
- (setq v (bf-times (bf-times v v) (coerce n *domain*)))
- (setq u (bf-difference u (cut!ep v (- k2))))
- (setq n (* 2 n)))
- (setq v (cut!mt (bf-expt (bf-plus x y) 2 k2) k2))
- (setq u (bf-quotient v (bf-times (coerce 4 *domain*) u) k))
- (save!const '!pi u)
- u))
-
- ;; This function calculates the value of 'E', the base of the natural
- ;; logarithm, with precision K, by summing the Taylor series for
- ;; EXP(X=1).
- (defmethod e-value ((domain real-numbers))
- (bind-domain-context domain
- (bf-e (fp-precision domain))))
-
- (defun bf-e (precision)
- (cond ((not (> precision 20))
- (round!mt (make-bigfloat *domain* 271828182845904523536 -20)
- precision))
- (t (let* ((u (get!const '!e precision))
- (k2 (+ precision 2))
- (m 1)
- (n (expt 10 k2))
- (ans 0))
- (when (null u)
- (loop while (not (lisp:zerop n))
- do (incf ans (setq n (lisp:truncate n (incf m)))))
- (setq ans (+ ans (* 2 (expt 10 k2))))
- (setq u (round!mt (make-bigfloat *domain* ans (- k2))
- precision))
- (save!const '!e u))
- u))))
-
- ;;; Elementary Functions.
-
- ;; This function calculates the square root of X with the precision K,
- ;; by Newton's iteration method.
- (defmethod sqrt ((number bigfloat))
- (bind-domain-context (domain-of number)
- (bf-sqrt number (fp-precision *domain*))))
-
- (defun bf-sqrt (x k)
- (if (0? x) (coerce 0 *domain*)
- (let* ((k2 (+ k 2))
- (ncut (- k2 (lisp:truncate (1+ (order! x)) 2)))
- (half (coerce 0.5 *domain*))
- (dcut (make-bigfloat *domain* 10 (- ncut)))
- (dy (make-bigfloat *domain* 20 (- ncut)))
- (nfig 1)
- (y0 (conv!mt x 2))
- y u)
- (setq y0 (if (lisp:zerop (rem (bigfloat-exponent y0) 2))
- (make-bigfloat *domain*
- (+ 3 (* 2 (lisp:truncate (bigfloat-mantissa y0) 25)))
- (lisp:truncate (bigfloat-exponent y0) 2))
- (make-bigfloat *domain*
- (+ 10 (* 2 (lisp:truncate (bigfloat-mantissa y0) 9)))
- (lisp:truncate (- (bigfloat-exponent y0) 1) 2))))
- (loop while (or (< nfig k2)
- (> (bf-abs dy) dcut))
- do (if (> (setq nfig (* 2 nfig)) k2)
- (setq nfig k2))
- (setq u (bf-quotient x y0 nfig))
- (setq y (bf-times (bf-plus y0 u) half))
- (setq dy (bf-difference y y0))
- (setq y0 y))
- (round!mt y k))))
-
-
- ;; This function calculates the value of the exponential function at
- ;; the point 'x', with the precision k, by summing terms of the Taylor
- ;; series for exp(z), 0 < z < 1.
- (defmethod exp ((number bigfloat))
- (bind-domain-context (domain-of number)
- (bf-exp number (fp-precision *domain*))))
-
- (defun bf-exp (x k)
- (cond ((0? x) (coerce 1 *domain*))
- (t (let* ((k2 (+ k 2))
- (one (coerce 1 *domain*))
- (y (bf-abs x))
- (m (floor y))
- (q (coerce m *domain*))
- (r (bf-difference y q))
- yq yr)
- (setq yq (if (lisp:zerop m) one
- (bf-expt (bf-e k2) m k2)))
- (cond ((0? r) (setq yr one))
- (t (let ((j 0) (n 0)
- (dcut (make-bigfloat *domain* 10 (- k2)))
- (ri one) (tm one)
- fctrial)
- (setq yr one)
- (setq m 1)
- (loop while (> tm dcut) do
- (setq fctrial
- (coerce
- (setq m (* m (setq j (1+ j)))) *domain*))
- (setq ri (cut!ep (bf-times ri r) (- k2)))
- (setq n (max 1 (+ (- k2 (order! fctrial))
- (order! ri))))
- (setq tm (bf-quotient ri fctrial n))
- (setq yr (bf-plus yr tm))
- (cond ((lisp:zerop (rem j 10))
- (setq yr (cut!ep yr (- k2)))))))))
- (setq y (cut!mt (bf-times yq yr) (1+ k)))
- (if (minus? x) (bf-quotient one y k)
- (round!last y))))))
-
-
- ;; This function calculates log(x) by summing terms of the
- ;; Taylor series for LOG(1+Z), 0 < Z < 0.10518.
- (defmethod log ((x bigfloat))
- (let ((domain (domain-of x)))
- (bind-domain-context domain
- (bf-log x (fp-precision domain)))))
-
- (defmethod-binary log2 bigfloat (x base)
- (let ((k2 (+ 2 (fp-precision domain))))
- (bind-domain-context domain
- (bf-quotient (bf-log x k2) (bf-log base k2) (- k2 2)))))
-
- (defun bf-log (x k)
- (when (not (plus? x))
- (error "Invalid argument to log: ~S" x))
- (unless (and (integerp k) (> k 0))
- (error "Invalid precision to log: ~D" k))
- (cond ((= x 1)
- (coerce 0 *domain*))
- (t (let* ((m 0)
- (k2 (+ k 2))
- (one (coerce 1 *domain*))
- (ee (bf-e k2))
- (es (bf-exp (coerce 0.1 *domain*) k2))
- sign l y z)
- (cond ((> x one) (setq sign one) (setq y x))
- (t (setq sign (bf-minus one))
- (setq y (bf-quotient one x k2))))
- (cond ((< y ee)
- (setq z y))
- (t
- (cond ((lisp:zerop (setq m (lisp:truncate (* (order! y) 23)
- 10)))
- (setq z y))
- (t (setq z (bf-quotient y (bf-expt ee m k2) k2))))
- (loop while (> z ee) do
- (setq m (1+ m))
- (setq z (bf-quotient z ee k2)))))
- (setq l (coerce m *domain*))
- (setq y (coerce 0.1 *domain*))
- (loop while (> z es) do
- (setq l (bf-plus l y))
- (setq z (bf-quotient z es k2)))
- (setq z (bf-difference z one))
- (prog (n dcut tm zi)
- (setq n 0)
- (setq y (setq tm (setq zi z)))
- (setq z (bf-minus z))
- (setq dcut (make-bigfloat *domain* 10 (- k2)))
- (setq m 1)
- (loop while (> (bf-abs tm) dcut) do
- (setq zi (cut!ep (bf-times zi z) (- k2)))
- (setq n (max 1 (+ k2 (order! zi))))
- (setq tm
- (bf-quotient zi (coerce (setq m (1+ m)) *domain*)
- n))
- (setq y (bf-plus y tm))
- (cond ((lisp:zerop (rem m 10))
- (setq y (cut!ep y (- k2)))))))
- (setq y (bf-plus y l))
- (round!mt (bf-times sign y) k)))))
-
- ;; This function calculates log(x), the value of the logarithmic
- ;; function at the point 'x', with the precision k, by solving x =
- ;; exp(y) by Newton's method.
- ;; x > 0, k is a positive integer
- #+Ignore
- (defun bf-log-newton (x k)
- (when (not (plus? x))
- (error "Invalid argument to log: ~S" x))
- (unless (and (integerp k) (> k 0))
- (error "Invalid precision to log: ~D" k))
- (cond ((bf-equal x (coerce 1 *domain*))
- (coerce 0 *domain*))
- (t (let* ((k2 (+ k 2))
- m (one (coerce 1 *domain*))
- (ee (bf-e (+ k2 2)))
- sign y z)
- (cond ((> x one)
- (setq sign one)
- (setq y x))
- (t (setq sign (bf-minus one))
- (setq y (bf-quotient one x k2))))
- (if (< y ee)
- (setq m 0 z y)
- (cond ((lisp:zerop
- (setq m (lisp:truncate (lisp:* (order! y) 23) 10)))
- (setq z y))
- (t (setq z (bf-quotient y (bf-expt ee m k2) k2))
- (loop while (> z ee) do
- (setq m (1+ m))
- (setq z (bf-quotient z ee k2))))))
- (let ((nfig 0) (n 0)
- (dcut (make-bigfloat *domain* 10 (- k2)))
- dx
- (dy (make-bigfloat *domain* 20 (- k2)))
- x0)
- (setq y (bf-quotient (bf-difference z one)
- (coerce 1.72 *domain*) 2))
- (setq nfig 1)
- (loop while (or (< nfig k2) (> (bf-abs dy) dcut)) do
- (cond
- ((> (setq nfig (* 2 nfig)) k2)
- (setq nfig k2)))
- (setq x0 (exp* y nfig))
- (setq dx (bf-difference z x0))
- (setq n (max 1 (+ nfig (order! dx))))
- (setq dy (bf-quotient dx x0 n))
- (setq y (bf-plus y dy))))
- (setq y (bf-plus (coerce m *domain*) y))
- (round!mt (bf-times sign y) k)))))
-
- ;; This function calculates sin(x), the value of the sine function at
- ;; the point 'x', with the precision k, by summing terms of the Taylor
- ;; series for: sin(z), 0 < Z < PI/4.
- (defmethod sin ((number bigfloat))
- (let ((domain (domain-of number)))
- (bind-domain-context domain
- (bf-sin number (fp-precision domain)))))
-
- (defun bf-sin (x k)
- (cond ((0? x) (coerce 0 *domain*))
- ((minus? x) (bf-minus (bf-sin (bf-minus x) k)))
- (t (let* ((k2 (+ k 2))
- (m (preci! x))
- (pi4 (bf-times (bf-pi (+ k2 m)) (coerce 0.25 *domain*)))
- sign q r y)
- (cond ((< x pi4)
- (setq m 0)
- (setq r x))
- (t (setq m (floor (setq q (bf-floor x pi4))))
- (setq r (bf-difference x (bf-times q pi4)))))
- (setq sign (coerce 1 *domain*))
- (cond ((not (< m 8)) (setq m (rem m 8))))
- (cond ((not (< m 4))
- (setq sign (bf-minus sign))
- (setq m (- m 4))))
- (cond ((equal m 1)
- (setq r (cut!mt (bf-difference pi4 r) k2))
- (bf-times sign (bf-cos r k)))
- ((equal m 2)
- (setq r (cut!mt r k2))
- (bf-times sign (bf-cos r k)))
- (t (unless (equal m 0)
- (setq r (cut!mt (bf-difference pi4 r) k2)))
- (let* ((ncut (- k2 (min 0 (1+ (order! r)))))
- (dcut (make-bigfloat *domain* 10 (- ncut)))
- (tm r) (ri r) (j 1) n fctrial)
- (setq y r)
- (setq r (bf-minus (cut!ep (bf-times r r) (- ncut))))
- (setq m 1)
- (loop while (> (bf-abs tm) dcut) do
- (setq j (+ j 2))
- (setq fctrial
- (coerce
- (setq m (* m j (1- j))) *domain*))
- (setq ri (cut!ep (bf-times ri r) (- ncut)))
- (setq n (max 1 (+ (- k2 (order! fctrial)) (order! ri))))
- (setq tm (bf-quotient ri fctrial n))
- (setq y (bf-plus y tm))
- (cond ((lisp:zerop (rem j 20))
- (setq y (cut!ep y (- ncut)))))))
- (round!mt (bf-times sign y) k)))))))
-
- ;; This function calculates cos(x), the value of the cosine function at
- ;; the point 'x', with the precision k, by summing terms of the Taylor
- ;; series for: cos(z), 0 < Z < PI/4.
- (defmethod cos ((number bigfloat))
- (let ((domain (domain-of number)))
- (bind-domain-context domain
- (bf-cos number (fp-precision domain)))))
-
- (defun bf-cos (x k)
- (unless (and (integerp k) (> k 0))
- (error "Invalid precision to cos: ~D" k))
- (cond ((0? x) (coerce 1 *domain*))
- (t (when (minus? x)
- (setq x (- x)))
- (let* ((k2 (+ k 2))
- (m (preci! x))
- (pi4 (/ (bf-pi (+ k2 m)) 4))
- sign q r y)
- (cond ((< x pi4)
- (setq m 0)
- (setq r x))
- (t (setq m (floor (setq q (floor x pi4))))
- (setq r (- x (* q pi4)))))
- (setq sign (coerce 1 *domain*))
- (cond ((not (< m 8)) (setq m (rem m 8))))
- (cond ((not (< m 4))
- (setq sign (- sign))
- (setq m (- m 4))))
- (cond ((not (< m 2)) (setq sign (- sign))))
- (cond ((equal m 1)
- (setq r (cut!mt (- pi4 r) k2))
- (bf-times sign (bf-sin r k)))
- ((equal m 2)
- (setq r (cut!mt r k2))
- (bf-times sign (bf-sin r k)))
- (t (when (= m 3)
- (setq r (cut!mt (- pi4 r) k2)))
- (let ((j 0) (n 0)
- (dcut (make-bigfloat *domain* 10 (- k2)))
- fctrial ri tm)
- (setq y (setq ri (setq tm (coerce 1 *domain*))))
- (setq r (- (cut!ep (* r r) (- k2))))
- (setq m 1)
- (loop while (> (bf-abs tm) dcut) do
- (setq j (+ j 2))
- (setq fctrial
- (coerce
- (setq m (* m j (- j 1))) *domain*))
- (setq ri (cut!ep (* ri r) (- k2)))
- (setq n (max 1 (+ (- k2 (order! fctrial))
- (order! ri))))
- (setq tm (bf-quotient ri fctrial n))
- (setq y (+ y tm))
- (cond ((equal (rem j 20) 0)
- (setq y (cut!ep y (- k2)))))))
- (round!mt (* sign y) k)))))))
-
- ;; This function calculates tan(x), the value of the tangent function
- ;; at the point 'x', with the precision k, by calculating
- ;; sin(x) or cos(x) = sin(pi/2-x).
- (defmethod tan ((number bigfloat))
- (let ((domain (domain-of number)))
- (bind-domain-context domain
- (bf-tan number (fp-precision domain)))))
-
- (defun bf-tan (x k)
- (unless (and (integerp k) (> k 0))
- (error "Invalid precision to tan: ~D" k))
- (cond ((0? x) (coerce 0 *domain*))
- ((minus? x) (bf-minus (bf-tan (bf-minus x) k)))
- (t (let* ((k2 (+ k 2))
- (one (coerce 1 *domain*))
- (m (preci! x))
- (pi4 (bf-times (bf-pi (+ k2 m)) (coerce 0.25 *domain*)))
- sign q r)
- (cond ((< x pi4)
- (setq m 0)
- (setq r x))
- (t (setq m (floor (setq q (bf-floor x pi4))))
- (setq r (bf-difference x (bf-times q pi4)))))
- (cond ((not (< m 4)) (setq m (rem m 4))))
- (setq sign (if (< m 2) one (bf-minus one)))
- (cond ((or (= m 1) (= m 3))
- (setq r (bf-difference pi4 r))))
- (setq r (cut!mt r k2))
- (cond ((or (equal m 0) (equal m 3))
- (setq r (bf-sin r k2))
- (setq q (bf-difference one (bf-times r r)))
- (setq q (bf-sqrt (cut!mt q k2) k2))
- (bf-times sign (bf-quotient r q k)))
- (t (setq r (bf-sin r k2))
- (setq q (bf-difference one (bf-times r r)))
- (setq q (bf-sqrt (cut!mt q k2) k2))
- (bf-times sign (bf-quotient q r k))))))))
-
- ;; This function calculates asin(x), the value of the arcsine function
- ;; at the point 'x', with the precision k, by calculating
- ;; atan(x/sqrt(1-x**2))
- ;; The answer is in the range <-pi/2 , pi/2>.
- (defmethod asin ((number bigfloat))
- (let ((domain (domain-of number)))
- (bind-domain-context domain
- (bf-asin number (fp-precision domain)))))
-
- (defun bf-asin (x k)
- (when (or (> (bf-abs x) (coerce 1 *domain*)))
- (error "Invalid argument to asin: ~S" x))
- (unless (and (integerp k) (> k 0))
- (error "Invalid precision to asin: ~D" k))
- (cond ((minus? x) (bf-minus (bf-asin (bf-minus x) k)))
- (t (let ((k2 (+ k 2))
- (one (coerce 1 *domain*)))
- (cond ((< (bf-difference one x)
- (make-bigfloat *domain* 10 (- k2)))
- (round!mt (bf-times (bf-pi (1+ k)) (coerce 0.5 *domain*))
- k))
- (t (bf-atan
- (bf-quotient x (bf-sqrt (cut!mt (- 1 (* x x)) k2) k2)
- k2)
- k)))))))
-
-
- ;; This function calculates acos(x), the value of the arccosine
- ;; function at the point 'x', with the precision k, by calculating
- ;; atan(sqrt(1-x**2)/x) if x > 0 or
- ;; atan(sqrt(1-x**2)/x) + pi if x < 0.
- ;; the answer is in the range [0 , pi).
- (defmethod acos ((number bigfloat))
- (let ((domain (domain-of number)))
- (bind-domain-context domain
- (bf-acos number (fp-precision domain)))))
-
- (defun bf-acos (x k)
- (when (or (> (bf-abs x) (coerce 1 *domain*)))
- (error "Invalid argument to acos: ~S" x))
- (unless (and (integerp k) (> k 0))
- (error "Invalid precision to acos: ~D" k))
- (let ((k2 (+ k 2))
- y)
- (cond ((< (bf-abs x) (make-bigfloat *domain* 50 (- k2)))
- (round!mt (bf-times (bf-pi (+ k 1)) (coerce 0.5 *domain*))
- k))
- (t (setq y (bf-quotient
- (bf-sqrt (cut!mt
- (bf-difference (coerce 1 *domain*)
- (bf-times x x))
- k2) k2)
- (bf-abs x)
- k2))
- (if (minus? x)
- (round!mt (bf-difference (bf-pi (+ k 1)) (bf-atan y k))
- k)
- (bf-atan y k))))))
-
- ;; this function calculates atan(x), the value of the arctangent
- ;; function at the point 'x', with the precision k, by summing terms
- ;; of the Taylor series for atan(z) if 0 < z < 0.42.
- ;; otherwise the following identities are used!
- ;; atan(x) = pi/2 - atan(1/x) if 1 < x and
- ;; atan(x) = 2*atan(x/(1+sqrt(1+x**2)))
- ;; if 0.42 <= x <= 1.
- ;; the answer is in the range [-pi/2, pi/2).
- (defmethod atan ((number bigfloat) &optional base)
- (when base
- (error "Two argument atan not implemented yet"))
- (let ((domain (domain-of number)))
- (bind-domain-context domain
- (bf-atan number (fp-precision domain)))))
-
- (defun bf-atan (x k)
- (unless (and (integerp k) (> k 0))
- (error "Invalid precision to atan: ~D" k))
- (cond ((0? x) (coerce 0 *domain*))
- ((minus? x) (bf-minus (bf-atan (bf-minus x) k)))
- (t (let* ((k2 (+ k 2))
- (one (coerce 1 *domain*))
- (pi4 (bf-times (bf-pi k2) (coerce 0.25 *domain*)))
- y z)
- (cond ((= x 1)
- (round!mt pi4 k))
- ((> x one)
- (round!mt
- (bf-difference (bf-plus pi4 pi4)
- (bf-atan (bf-quotient one x k2) (+ k 1)))
- k))
- ((< x (coerce 0.42 *domain*))
- (let* ((m 1) (n 0)
- (ncut (- k2 (min 0 (+ (order! x) 1))))
- (dcut (make-bigfloat *domain* 10 (- ncut)))
- (zi x)
- (tm x))
- (setq y tm)
- (setq z (bf-minus (cut!ep (bf-times x x) (- ncut))))
- (loop while (> (bf-abs tm) dcut) do
- (setq zi (cut!ep (bf-times zi z) (- ncut)))
- (setq n (max 1 (+ k2 (order! zi))))
- (setq tm (bf-quotient
- zi (coerce (setq m (+ m 2)) *domain*)
- n))
- (setq y (bf-plus y tm))
- (cond ((lisp:zerop (rem m 20))
- (setq y (cut!ep y (- ncut)))))))
- (round!mt y k))
- (t (setq y (bf-plus one (cut!mt (bf-times x x) k2)))
- (setq y (bf-plus one (bf-sqrt y k2)))
- (setq y (bf-atan (bf-quotient x y k2) (+ k 1)))
- (round!mt (bf-times y (coerce 2 *domain*)) k)))))))
-
- ;; this function calculates arcsin(x), the value of the arcsine
- ;; function at the point 'x', with the precision k, by solving
- ;; x = sin(y) if 0 < x <= 0.72, or
- ;; sqrt(1-x**2) = sin(y) if 0.72 < x,
- ;; by Newton's iteration method.
- ;; the answer is in the range [-pi/2, pi/2).
- #+Ignore
- (defun bf-asin-newton (x k)
- (when (or (> (bf-abs x) (coerce 1 *domain*)))
- (error "Invalid argument to asin: ~S" x))
- (unless (and (integerp k) (> k 0))
- (error "Invalid precision to asin: ~D" k))
- (cond ((0? x) (coerce 0 *domain*))
- ((minus? x) (bf-minus (bf-asin-newton (bf-minus x) k)))
- (t (let* ((k2 (+ k 2))
- (dcut (make-bigfloat *domain* 10 (+ (- k2) (order! x) 1)))
- (one (coerce 1 *domain*))
- (pi2 (bf-times (bf-pi (+ k2 2)) (coerce 0.5 *domain*)))
- y)
- (cond ((< (- 1 x) dcut)
- (round!mt pi2 k))
- ((> x (coerce 0.72 *domain*))
- (setq y (cut!mt (bf-difference one (bf-times x x)) k2))
- (setq y (bf-asin-newton (bf-sqrt y k2) k))
- (round!mt (bf-difference pi2 y) k))
- (t (let ((nfig 1)
- (n 0)
- (dy one)
- cx dx x0)
- (setq y x)
- (loop while (or (< nfig k2)
- (> (bf-abs dy) dcut))
- do (cond ((> (setq nfig (* 2 nfig)) k2)
- (setq nfig k2)))
- (setq x0 (bf-sin y nfig))
- (setq cx (bf-sqrt (cut!mt (- 1 (* x0 x0))
- nfig)
- nfig))
- (setq dx (- x x0))
- (setq n (max 1 (+ nfig (order! dx))))
- (setq dy (bf-quotient dx cx n))
- (setq y (bf-plus y dy)))
- (round!mt y k))))))))
-
- ;; This function calculates arccos(x), the value of the arccosine
- ;; function at the point 'x', with the precision k, by calculating
- ;; arcsin(sqrt(1-x**2)) if x > 0.72 and
- ;; pi/2 - arcsin(x) otherwise.
- ;; The answer is in the range [0, pi).
- #+ignore
- (defun bf-acos-newton (x k)
- (when (or (> (bf-abs x) (coerce 1 *domain*)))
- (error "Invalid argument to acos: ~S" x))
- (unless (and (integerp k) (> k 0))
- (error "Invalid precision to acos: ~D" k))
- (cond ((bf-<= x (coerce 0.72 *domain*))
- (round!mt
- (bf-difference
- (bf-times (bf-pi (+ k 1)) (coerce 0.5 *domain*))
- (bf-asin-newton x k))
- k))
- (t (bf-asin-newton
- (bf-sqrt
- (cut!mt (bf-difference (coerce 1 *domain*) (* x x))
- (+ k 2))
- (+ k 2))
- k))))
-
- ;; This function calculates arctan(x), the value of the arctangent
- ;; function at the point 'x', with the precision k, by calculating
- ;; arcsin(x/sqrt(1+x**2))
- ;; The answer is in the range [-pi/2, pi/2).
- #+Ignore
- (defun bf-atan-newton (x k)
- (unless (and (integerp k) (> k 0))
- (error "Invalid precision to atan: ~D" k))
- (cond ((minus? x) (bf-minus (bf-atan-newton (bf-minus x) k)))
- (t (bf-asin-newton
- (bf-quotient x (bf-sqrt (cut!mt (+ 1 (* x x)) (+ k 2))
- (+ k 2))
- (+ k 2))
- k))))
-
- (defmethod-binary expt bigfloat (x y)
- (bind-domain-context domain
- (cond ((bf-integerp y) (expt x (floor y)))
- ((minus? y)
- (/ 1 (expt x (bf-minus y))))
- (t (let ((n (fp-precision domain))
- (xp (abs x))
- yp)
- (cond ((bf-integerp (bf-times y (coerce 2 domain)))
- (setq xp (incprec! xp 1))
- (setq yp (round!mt
- (bf-times (expt xp (floor y))
- (bf-sqrt xp (+ n 1)))
- n)))
- (t (setq yp (bf-exp (* y (bf-log xp (1+ n))) n))))
- (cond ((minus? x) (bf-minus yp)) (t yp)))))))
-
-